import os  # 导入操作系统接口模块，用于文件路径检查和文件操作
import datetime  # 导入日期时间模块，用于记录学生报道的具体时间
import hashlib  # 导入哈希算法模块，用于对用户密码进行SHA256加密
import re  # 导入正则表达式模块，用于验证输入数据的格式是否正确
from prettytable import PrettyTable  # 从prettytable库导入PrettyTable类，用于在控制台中创建格式化的表格显示

class DataStorage:  # 定义数据存储类，负责管理所有文件的读写操作
    def __init__(self):  # 类的构造函数，在创建DataStorage对象时自动调用
        self.users_file = 'users.txt'  # 设置用户账户信息存储文件名，包含用户名、密码、类型
        self.students_file = 'students.txt'  # 设置学生基本信息存储文件名，包含学号、姓名、专业等
        self.dormitories_file = 'dormitories.txt'  # 设置宿舍信息存储文件名，包含宿舍号、楼栋、类型、容量
        self.registration_file = 'registration_records.txt'  # 设置报道记录存储文件名，记录学生报道时间和经办人
    
    def validate_input(self, text, field_name, min_length=1, max_length=50):  # 定义输入验证方法，检查文本输入是否符合要求
        if not text or not text.strip():  # 使用not运算符检查输入是否为空字符串或只包含空白字符
            raise ValueError(f'{field_name}不能为空')  # 如果输入为空则抛出ValueError异常，提示用户该字段不能为空
        text = text.strip()  # 调用strip()方法去除字符串首尾的空白字符（空格、制表符、换行符）
        if len(text) < min_length:  # 使用len()函数检查字符串长度是否小于最小长度要求
            raise ValueError(f'{field_name}长度不能少于{min_length}个字符')  # 如果长度不足则抛出异常提示最小长度要求
        if len(text) > max_length:  # 检查字符串长度是否超过最大长度限制
            raise ValueError(f'{field_name}长度不能超过{max_length}个字符')  # 如果超长则抛出异常提示最大长度限制
        if '|' in text:  # 检查文本中是否包含竖线字符，因为竖线是我们的数据分隔符
            raise ValueError(f'{field_name}不能包含竖线字符(|)')  # 如果包含竖线则抛出异常，防止破坏数据格式
        return text  # 验证通过后返回清理后的文本字符串
    
    def validate_student_id(self, student_id):  # 定义学号验证方法，确保学号格式符合规范
        student_id = self.validate_input(student_id, '学号', 8, 20)  # 调用通用验证方法，要求学号长度在8-20字符之间
        if not re.match(r'^[a-zA-Z0-9]+$', student_id):  # 使用正则表达式检查学号是否只包含英文字母和数字
            raise ValueError('学号只能包含数字和字母')  # 如果包含其他字符则抛出异常提示格式错误
        return student_id  # 验证通过后返回学号字符串
    
    def validate_phone(self, phone):  # 定义电话号码验证方法，检查电话号码格式是否正确
        phone = self.validate_input(phone, '联系电话', 7, 15)  # 调用通用验证方法，要求电话号码长度在7-15字符之间
        if not re.match(r'^[0-9\-\s]+$', phone):  # 使用正则表达式检查电话号码是否只包含数字、短横线和空格
            raise ValueError('电话号码格式不正确')  # 如果包含其他字符则抛出异常提示格式错误
        return phone  # 验证通过后返回电话号码字符串
    
    def validate_capacity(self, capacity_str):  # 定义宿舍容量验证方法，确保容量是有效的正整数
        try:  # 使用try-except结构捕获可能的转换异常
            capacity = int(capacity_str)  # 尝试将字符串转换为整数类型
            if capacity <= 0 or capacity > 10:  # 检查容量是否在合理范围内（1-10人）
                raise ValueError('宿舍容量必须在1-10人之间')  # 如果超出范围则抛出异常
            return capacity  # 验证通过后返回整数类型的容量值
        except ValueError:  # 捕获int()转换失败的异常
            raise ValueError('宿舍容量必须是有效数字')  # 抛出自定义异常提示用户输入有效数字
    def save_user(self, username, password, user_type):  # 定义保存用户信息到文件的方法
        try:  # 使用try-except结构处理可能的文件操作异常
            with open(self.users_file, 'a', encoding='utf-8') as f:  # 以追加模式打开用户文件，使用UTF-8编码支持中文
                f.write(f"{username}|{password}|{user_type}\n")  # 将用户信息按"用户名|密码|类型"格式写入文件，换行符结尾
        except IOError as e:  # 捕获文件输入输出异常
            raise IOError(f"保存用户信息失败: {e}")  # 重新抛出异常并提供更友好的错误信息
    
    def load_users(self):  # 从文件加载所有用户账户信息，返回用户信息字典
        users = {}  # 初始化空字典存储用户信息，键为用户名，值为包含密码和类型的字典
        if os.path.exists(self.users_file):  # 检查用户文件是否存在，避免首次运行时出错
            try:  # 使用try-except结构处理文件读取可能的异常
                with open(self.users_file, 'r', encoding='utf-8') as f:  # 以只读模式打开文件，使用UTF-8编码读取中文字符
                    for line_num, line in enumerate(f, 1):  # 逐行读取用户数据，enumerate提供行号用于错误提示
                        parts = line.strip().split('|')  # 去除行尾换行符并按竖线分割字段
                        if len(parts) == 3:  # 验证数据格式完整性（必须有3个字段）
                            users[parts[0]] = {  # 将用户信息添加到字典中，以用户名为键
                                'password': parts[1],  # 加密后的密码存储在password字段
                                'type': parts[2]       # 用户类型存储在type字段
                            }
                        else:  # 当数据格式错误时
                            print(f"警告: 用户文件第{line_num}行数据格式错误，已跳过")  # 输出警告信息但不中断程序执行
            except IOError as e:  # 捕获文件读取异常
                raise IOError(f"读取用户信息失败: {e}")  # 重新抛出异常并提供更友好的错误信息
        return users  # 返回包含所有用户信息的字典
    
    def save_student(self, student_id, name, major, phone, address, status='未报道'):  # 保存学生基本信息到文件，默认报道状态为未报道
        try:  # 使用try-except结构处理可能的异常
            student_id = self.validate_student_id(student_id)  # 验证学号格式的有效性
            name = self.validate_input(name, '姓名', 2, 20)  # 验证姓名输入，长度2-20字符
            major = self.validate_input(major, '专业', 2, 30)  # 验证专业输入，长度2-30字符
            phone = self.validate_phone(phone)  # 验证电话号码格式
            address = self.validate_input(address, '地址', 5, 100)  # 验证地址输入，长度5-100字符
            with open(self.students_file, 'a', encoding='utf-8') as f:  # 以追加模式打开学生信息文件，使用UTF-8编码
                f.write(f"{student_id}|{name}|{major}|{phone}|{address}|{status}|未分配\n")  # 写入学生信息，格式为学号|姓名|专业|电话|地址|报道状态|宿舍号
        except IOError as e:  # 捕获文件操作异常
            raise IOError(f"保存学生信息失败: {e}")  # 重新抛出异常并提供友好的错误信息
        except ValueError as e:  # 捕获数据验证异常
            raise e  # 重新抛出验证错误，保持原有的错误信息
    
    def load_students(self):  # 从文件加载所有学生信息，返回学生信息字典
        students = {}  # 初始化空字典存储学生信息，键为学号，值为包含学生详细信息的字典
        if os.path.exists(self.students_file):  # 检查学生文件是否存在
            try:  # 使用try-except结构处理文件读取异常
                with open(self.students_file, 'r', encoding='utf-8') as f:  # 以只读模式打开学生文件，使用UTF-8编码
                    for line_num, line in enumerate(f, 1):  # 逐行读取学生数据，enumerate提供行号
                        parts = line.strip().split('|')  # 分割数据字段，使用竖线作为分隔符
                        if len(parts) >= 6:  # 验证数据完整性（至少需要6个字段）
                            students[parts[0]] = {  # 构建学生信息字典，以学号为键
                                'name': parts[1],      # 学生姓名
                                'major': parts[2],     # 专业
                                'phone': parts[3],     # 联系电话
                                'address': parts[4],   # 家庭地址
                                'status': parts[5],    # 报道状态
                                'dormitory': parts[6] if len(parts) > 6 else '未分配'  # 宿舍信息，如果没有第7个字段则默认为未分配
                            }
                        else:  # 当数据格式错误时
                            print(f"警告: 学生文件第{line_num}行数据格式错误，已跳过")  # 输出警告但不中断程序
            except IOError as e:  # 捕获文件读取异常
                raise IOError(f"读取学生信息失败: {e}")  # 重新抛出异常并提供友好错误信息
        return students  # 返回包含所有学生信息的字典
    
    def update_students_file(self, students):  # 更新学生信息文件（重写整个文件），用于修改学生信息后同步到文件中
        try:  # 使用try-except结构处理文件操作异常
            with open(self.students_file, 'w', encoding='utf-8') as f:  # 以写模式打开文件，会覆盖原有内容，使用UTF-8编码
                for student_id, info in students.items():  # 遍历所有学生信息字典中的键值对
                    f.write(f"{student_id}|{info['name']}|{info['major']}|{info['phone']}|{info['address']}|{info['status']}|{info['dormitory']}\n")  # 按格式写入学生信息到文件
        except IOError as e:  # 捕获文件操作异常
            raise IOError(f"更新学生信息文件失败: {e}")  # 重新抛出异常并提供友好错误信息
    
    def save_dormitory(self, dorm_id, building, room_type, capacity, occupied=0):  # 保存宿舍信息到文件，默认已住人数为0
        try:  # 使用try-except结构处理可能的异常
            dorm_id = self.validate_input(dorm_id, '宿舍号', 3, 20)  # 验证宿舍号输入，长度3-20字符
            building = self.validate_input(building, '楼栋', 1, 20)  # 验证楼栋输入，长度1-20字符
            room_type = self.validate_input(room_type, '房间类型', 2, 20)  # 验证房间类型输入，长度2-20字符
            with open(self.dormitories_file, 'a', encoding='utf-8') as f:  # 以追加模式打开宿舍文件，使用UTF-8编码
                f.write(f"{dorm_id}|{building}|{room_type}|{capacity}|{occupied}\n")  # 按格式写入宿舍信息：宿舍号|楼栋|房间类型|容量|已住人数
        except IOError as e:  # 捕获文件操作异常
            raise IOError(f"保存宿舍信息失败: {e}")  # 重新抛出异常并提供友好错误信息
        except ValueError as e:  # 捕获数据验证异常
            raise e  # 重新抛出验证错误
    
    def load_dormitories(self):  # 从文件加载所有宿舍信息，返回宿舍信息字典
        dormitories = {}  # 初始化空字典存储宿舍信息，键为宿舍号，值为宿舍详细信息
        if os.path.exists(self.dormitories_file):  # 检查宿舍文件是否存在
            try:  # 使用try-except结构处理文件读取异常
                with open(self.dormitories_file, 'r', encoding='utf-8') as f:  # 以只读模式打开宿舍文件，使用UTF-8编码
                    for line_num, line in enumerate(f, 1):  # 逐行读取宿舍数据，enumerate提供行号
                        parts = line.strip().split('|')  # 分割数据字段，使用竖线作为分隔符
                        if len(parts) == 5:  # 验证数据完整性（必须有5个字段）
                            try:  # 使用try-except处理数值转换异常
                                dormitories[parts[0]] = {  # 构建宿舍信息字典，以宿舍号为键
                                    'building': parts[1],           # 楼栋名称
                                    'room_type': parts[2],          # 房间类型
                                    'capacity': int(parts[3]),      # 容量（转换为整数）
                                    'occupied': int(parts[4])       # 已住人数（转换为整数）
                                }
                            except ValueError:  # 捕获数值转换异常
                                print(f"警告: 宿舍文件第{line_num}行数据格式错误（数值转换失败），已跳过")  # 输出转换失败警告
                        else:  # 当字段数量不正确时
                            print(f"警告: 宿舍文件第{line_num}行数据格式错误，已跳过")  # 输出格式错误警告
            except IOError as e:  # 捕获文件读取异常
                raise IOError(f"读取宿舍信息失败: {e}")  # 重新抛出异常并提供友好错误信息
        return dormitories  # 返回包含所有宿舍信息的字典
    
    def update_dormitories_file(self, dormitories):  # 更新宿舍信息文件（重写整个文件），用于修改宿舍信息后同步到文件中
        try:  # 使用try-except结构处理文件操作异常
            with open(self.dormitories_file, 'w', encoding='utf-8') as f:  # 以写模式打开宿舍文件，会覆盖原有内容，使用UTF-8编码
                for dorm_id, info in dormitories.items():  # 遍历所有宿舍信息字典中的键值对
                    f.write(f"{dorm_id}|{info['building']}|{info['room_type']}|{info['capacity']}|{info['occupied']}\n")  # 按格式写入宿舍信息到文件
        except IOError as e:  # 捕获文件操作异常
            raise IOError(f"更新宿舍信息文件失败: {e}")  # 重新抛出异常并提供友好错误信息
    
    def save_registration_record(self, student_id, registration_time, operator):  # 保存学生报道记录到文件
        try:  # 使用try-except结构处理文件操作异常
            with open(self.registration_file, 'a', encoding='utf-8') as f:  # 以追加模式打开报道记录文件，使用UTF-8编码
                f.write(f"{student_id}|{registration_time}|{operator}\n")  # 按格式写入报道记录：学号|报道时间|经办人
        except IOError as e:  # 捕获文件操作异常
            raise IOError(f"保存报道记录失败: {e}")  # 重新抛出异常并提供友好错误信息
    
    def load_registration_records(self):  # 从文件加载所有报道记录，返回报道记录列表
        records = []  # 初始化空列表存储报道记录，每个元素是包含记录信息的字典
        if os.path.exists(self.registration_file):  # 检查报道记录文件是否存在
            try:  # 使用try-except结构处理文件读取异常
                with open(self.registration_file, 'r', encoding='utf-8') as f:  # 以只读模式打开报道记录文件，使用UTF-8编码
                    for line_num, line in enumerate(f, 1):  # 逐行读取报道记录数据，enumerate提供行号
                        parts = line.strip().split('|')  # 分割数据字段，使用竖线作为分隔符
                        if len(parts) == 3:  # 验证数据完整性（必须有3个字段）
                            records.append({  # 将记录信息添加到列表中
                                'student_id': parts[0],    # 学生学号
                                'time': parts[1],          # 报道时间
                                'operator': parts[2]       # 经办人
                            })
                        else:  # 当数据格式错误时
                            print(f"警告: 报道记录文件第{line_num}行数据格式错误，已跳过")  # 输出警告但不中断程序
            except IOError as e:  # 捕获文件读取异常
                raise IOError(f"读取报道记录失败: {e}")  # 重新抛出异常并提供友好错误信息
        return records  # 返回包含所有报道记录的列表

data_manager = DataStorage()  # 创建全局数据管理器实例，整个程序共享使用

class UserAuthentication:  # 用户认证管理类，负责用户注册、登录和密码安全
    @staticmethod
    def hash_password(password):  # 使用SHA256算法对密码进行哈希加密
        return hashlib.sha256(password.encode('utf-8')).hexdigest()  # 将密码字符串编码为字节，然后计算SHA256哈希值并返回十六进制字符串
    
    @staticmethod
    def validate_password(password):  # 验证密码强度和格式，密码必须至少6位，包含字母和数字
        if len(password) < 6:  # 检查密码长度是否少于6位
            raise ValueError('密码长度不能少于6位')  # 抛出异常提示密码太短
        if len(password) > 20:  # 检查密码长度是否超过20位
            raise ValueError('密码长度不能超过20位')  # 抛出异常提示密码太长
        if not re.search(r'[a-zA-Z]', password):  # 使用正则表达式检查是否包含字母
            raise ValueError('密码必须包含字母')  # 抛出异常提示必须包含字母
        if not re.search(r'\d', password):  # 使用正则表达式检查是否包含数字
            raise ValueError('密码必须包含数字')  # 抛出异常提示必须包含数字
        return password  # 验证通过后返回密码
    
    @staticmethod
    def register_user(username, password, user_type):  # 注册新用户账户的静态方法
        if not username or len(username.strip()) < 3:  # 验证用户名格式，检查长度是否至少3位
            raise ValueError('用户名长度不能少于3位')  # 抛出异常提示用户名太短
        if len(username) > 20:  # 检查用户名长度是否超过20位
            raise ValueError('用户名长度不能超过20位')  # 抛出异常提示用户名太长
        if not re.match(r'^[a-zA-Z0-9_]+$', username):  # 使用正则表达式检查用户名是否只包含字母、数字和下划线
            raise ValueError('用户名只能包含字母、数字和下划线')  # 抛出异常提示用户名包含非法字符
        UserAuthentication.validate_password(password)  # 调用密码验证方法检查密码强度
        users = data_manager.load_users()  # 加载现有用户信息检查用户名是否已存在
        if username in users:  # 检查用户名是否已经存在于系统中
            raise ValueError('用户名已存在')  # 抛出异常提示用户名重复
        encrypted_password = UserAuthentication.hash_password(password)  # 对密码进行SHA256加密
        data_manager.save_user(username, encrypted_password, user_type)  # 保存用户信息到文件
    
    @staticmethod
    def login_user(username, password):  # 用户登录验证的静态方法
        users = data_manager.load_users()  # 加载所有用户信息用于验证登录
        if username not in users:  # 检查用户是否存在于系统中
            raise ValueError('用户不存在')  # 抛出异常提示用户不存在
        encrypted_password = UserAuthentication.hash_password(password)  # 对输入密码进行SHA256加密
        if users[username]['password'] != encrypted_password:  # 比较加密后的密码与存储的密码是否一致
            raise ValueError('密码错误')  # 抛出异常提示密码错误
        return users[username]['type']  # 验证成功，返回用户类型

class StudentManager:  # 学生信息管理类，负责学生信息的增删改查和报道管理
    @staticmethod
    def register_student(student_id, name, major, phone, address):  # 注册新学生信息的静态方法
        students = data_manager.load_students()  # 加载现有学生信息检查学号是否重复
        if student_id in students:  # 检查学号是否已经存在，避免重复注册
            raise ValueError('学号已存在')  # 抛出异常提示学号重复
        data_manager.save_student(student_id, name, major, phone, address)  # 调用数据管理器保存学生信息
    
    @staticmethod
    def mark_registration(student_id, operator):  # 标记学生完成报道的静态方法
        students = data_manager.load_students()  # 加载学生信息用于检查学生是否存在和更新状态
        if student_id not in students:  # 检查学生是否存在于系统中
            raise ValueError('学生不存在')  # 抛出异常提示学生不存在
        if students[student_id]['status'] == '已报道':  # 检查学生的当前状态是否已经是已报道
            raise ValueError('该学生已经完成报道')  # 抛出异常提示学生已经报道过了
        students[student_id]['status'] = '已报道'  # 将学生的报道状态更新为已报道
        data_manager.update_students_file(students)  # 将更新后的学生信息写回文件保存
        registration_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')  # 获取当前时间并格式化为字符串作为报道时间
        data_manager.save_registration_record(student_id, registration_time, operator)  # 保存报道记录，包含学号、时间和经办人信息
    
    @staticmethod
    def get_student_info(student_id):  # 根据学号获取学生详细信息的静态方法
        students = data_manager.load_students()  # 从文件加载所有学生信息
        return students.get(student_id)  # 使用字典的get方法获取指定学号的学生信息，不存在时返回None
    
    @staticmethod
    def get_all_students():  # 获取所有学生信息的静态方法
        return data_manager.load_students()  # 直接调用数据管理器加载并返回包含所有学生信息的字典
    
    @staticmethod
    def get_statistics():  # 获取学生报道统计信息的静态方法
        students = data_manager.load_students()  # 加载所有学生信息用于统计
        total = len(students)  # 使用len函数计算学生总数
        registered = sum(1 for s in students.values() if s['status'] == '已报道')  # 使用生成器表达式和sum函数统计已报道的学生数量
        unregistered = total - registered  # 用总数减去已报道数量得到未报道人数
        return total, registered, unregistered  # 返回包含总人数、已报道人数、未报道人数的元组

class DormitoryManager:  # 宿舍管理类，负责宿舍信息管理和分配，提供添加宿舍、分配宿舍、查询可用宿舍等功能
    @staticmethod
    def add_dormitory(dorm_id, building, room_type, capacity):  # 添加新宿舍信息的静态方法
        dormitories = data_manager.load_dormitories()  # 加载现有宿舍信息用于检查宿舍号是否重复
        if dorm_id in dormitories:  # 检查宿舍号是否已经存在于系统中
            raise ValueError('宿舍号已存在')  # 抛出异常提示宿舍号重复
        if isinstance(capacity, str):  # 检查容量参数是否为字符串类型，需要转换为整数
            capacity = data_manager.validate_capacity(capacity)  # 调用数据管理器验证并转换容量为整数
        data_manager.save_dormitory(dorm_id, building, room_type, capacity)  # 调用数据管理器保存宿舍信息到文件
    
    @staticmethod
    def assign_dormitory(student_id, dorm_id):  # 为学生分配宿舍的静态方法
        students = data_manager.load_students()  # 加载学生信息用于验证和更新
        dormitories = data_manager.load_dormitories()  # 加载宿舍信息用于验证和更新
        if student_id not in students:  # 检查学生是否存在于系统中
            raise ValueError('学生不存在')  # 抛出异常提示学生不存在
        if dorm_id not in dormitories:  # 检查宿舍是否存在于系统中
            raise ValueError('宿舍不存在')  # 抛出异常提示宿舍不存在
        if students[student_id]['dormitory'] != '未分配':  # 检查学生是否已经分配过宿舍
            raise ValueError(f'该学生已分配宿舍: {students[student_id]["dormitory"]}')  # 抛出异常提示学生已有宿舍
        if dormitories[dorm_id]['occupied'] >= dormitories[dorm_id]['capacity']:  # 检查宿舍是否还有空余床位
            raise ValueError('宿舍已满')  # 抛出异常提示宿舍已满
        students[student_id]['dormitory'] = dorm_id  # 将宿舍号分配给学生
        dormitories[dorm_id]['occupied'] += 1  # 宿舍已住人数增加1
        data_manager.update_students_file(students)  # 更新学生信息文件
        data_manager.update_dormitories_file(dormitories)  # 更新宿舍信息文件
    
    @staticmethod
    def get_available_dormitories():  # 获取所有可用的宿舍（有空余床位的宿舍）的静态方法
        dormitories = data_manager.load_dormitories()  # 加载所有宿舍信息
        available = {}  # 初始化空字典存储可用宿舍信息
        for dorm_id, info in dormitories.items():  # 遍历所有宿舍信息的键值对
            if info['occupied'] < info['capacity']:  # 检查宿舍的已住人数是否小于容量，即是否有空余床位
                available[dorm_id] = info  # 将有空余床位的宿舍添加到可用宿舍字典中
        return available  # 返回包含所有可用宿舍信息的字典
    
    @staticmethod
    def get_all_dormitories():  # 获取所有宿舍信息的静态方法
        return data_manager.load_dormitories()  # 直接调用数据管理器加载并返回包含所有宿舍信息的字典

class SystemInterface:  # 系统用户界面类，负责处理所有用户交互和界面显示，提供完整的用户交互界面
    def __init__(self):  # 初始化系统界面的构造方法
        self.current_user = None    # 当前登录的用户名，初始值为None表示未登录
        self.user_type = None       # 当前用户的类型，用于区分管理员等不同权限用户
    
    def main_menu(self):  # 系统主菜单方法，提供用户登录、管理员注册等功能选择
        while True:  # 使用无限循环保持菜单持续显示，直到用户选择退出
            print("\n" + "="*40)  # 输出换行符和分隔线美化界面
            print("        高校新生报道系统")  # 输出系统标题居中显示
            print("="*40)  # 输出分隔线
            print("【1】用户登录")  # 显示用户登录选项
            print("【2】管理员注册")  # 显示管理员注册选项
            print("【3】退出系统")  # 显示退出系统选项
            print("="*40)  # 输出分隔线
            choice = input("请选择操作: ")  # 获取用户输入的选择
            if choice == '1':  # 如果用户选择1，执行登录功能
                self.login()  # 调用login方法处理用户登录
            elif choice == '2':  # 如果用户选择2，执行管理员注册功能
                self.register_admin()  # 调用register_admin方法处理管理员注册
            elif choice == '3':  # 如果用户选择3，退出系统
                print("谢谢使用，再见！")  # 输出退出提示信息
                break  # 跳出while循环，结束程序
            else:  # 如果用户输入其他无效选项
                print("无效选择，请重新输入")  # 提示用户输入无效，继续循环
    
    def register_admin(self):
        print("\n管理员注册")
        username = input("请输入用户名: ")
        password = input("请输入密码: ")
        confirm_password = input("请确认密码: ")
        
        if password != confirm_password:
            print("两次密码不一致")
            return
        
        try:
            UserAuthentication.register_user(username, password, 'admin')
            print("管理员注册成功")
        except ValueError as e:
            print(f"注册失败: {e}")
    
    def login(self):
        print("\n用户登录")
        username = input("请输入用户名: ")
        password = input("请输入密码: ")
        
        try:
            user_type = UserAuthentication.login_user(username, password)
            self.current_user = username
            self.user_type = user_type
            print(f"登录成功，欢迎 {username}")
            
            if user_type == 'admin':
                self.admin_menu()
            else:
                print("用户类型错误")
        except ValueError as e:
            print(f"登录失败: {e}")
    
    def admin_menu(self):
        while True:
            print("\n" + "="*40)
            print("        管理员操作面板")
            print("="*40)
            print("【1】学生信息管理")
            print("【2】宿舍管理")
            print("【3】报道管理")
            print("【4】统计查询")
            print("【5】返回主菜单")
            print("="*40)
            
            choice = input("请选择操作: ")
            
            if choice == '1':
                self.student_management()
            elif choice == '2':
                self.dormitory_management()
            elif choice == '3':
                self.registration_management()
            elif choice == '4':
                self.statistics_query()
            elif choice == '5':
                break
            else:
                print("无效选择，请重新输入")
    
    def student_management(self):
        while True:
            print("\n学生信息管理")
            print("【1】录入学生信息")
            print("【2】查看学生信息")
            print("【3】查看所有学生")
            print("【4】返回上级菜单")
            
            choice = input("请选择操作: ")
            
            if choice == '1':
                self.add_student()
            elif choice == '2':
                self.view_student()
            elif choice == '3':
                self.view_all_students()
            elif choice == '4':
                break
            else:
                print("无效选择，请重新输入")
    
    def add_student(self):
        print("\n录入学生信息")
        student_id = input("请输入学号: ")
        name = input("请输入姓名: ")
        major = input("请输入专业: ")
        phone = input("请输入联系电话: ")
        address = input("请输入家庭住址: ")
        
        try:
            StudentManager.register_student(student_id, name, major, phone, address)
            print("学生信息录入成功")
        except ValueError as e:
            print(f"录入失败: {e}")
    
    def view_student(self):
        print("\n查看学生信息")
        student_id = input("请输入学号: ")
        
        student = StudentManager.get_student_info(student_id)
        if student:
            table = PrettyTable(["项目", "信息"])
            table.add_row(["学号", student_id])
            table.add_row(["姓名", student['name']])
            table.add_row(["专业", student['major']])
            table.add_row(["电话", student['phone']])
            table.add_row(["地址", student['address']])
            table.add_row(["报道状态", student['status']])
            table.add_row(["宿舍", student['dormitory']])
            print(table)
        else:
            print("未找到该学生信息")
    
    def view_all_students(self):
        print("\n所有学生信息")
        students = StudentManager.get_all_students()
        
        if not students:
            print("暂无学生信息")
            return
        
        table = PrettyTable(["学号", "姓名", "专业", "电话", "报道状态", "宿舍"])
        for student_id, info in students.items():
            table.add_row([
                student_id, info['name'], info['major'], 
                info['phone'], info['status'], info['dormitory']
            ])
        print(table)
    
    def dormitory_management(self):
        while True:
            print("\n宿舍管理")
            print("【1】添加宿舍")
            print("【2】查看所有宿舍")
            print("【3】分配宿舍")
            print("【4】查看可用宿舍")
            print("【5】返回上级菜单")
            
            choice = input("请选择操作: ")
            
            if choice == '1':
                self.add_dormitory()
            elif choice == '2':
                self.view_all_dormitories()
            elif choice == '3':
                self.assign_dormitory()
            elif choice == '4':
                self.view_available_dormitories()
            elif choice == '5':
                break
            else:
                print("无效选择，请重新输入")
    
    def add_dormitory(self):  # 添加宿舍信息的用户界面方法
        print("\n" + "=" * 30)  # 输出分隔线美化界面
        print("         添加宿舍")  # 输出标题
        print("=" * 30)  # 输出分隔线
        try:  # 使用try-except结构处理可能的异常
            dorm_id = input("请输入宿舍号: ").strip()  # 收集宿舍号输入并去除首尾空格
            building = input("请输入楼栋: ").strip()  # 收集楼栋信息输入并去除首尾空格
            room_type = input("请输入房间类型: ").strip()  # 收集房间类型输入并去除首尾空格
            capacity_str = input("请输入容量(人数): ").strip()  # 收集容量输入并去除首尾空格
            capacity = data_manager.validate_capacity(capacity_str)  # 验证容量输入并转换为整数
            DormitoryManager.add_dormitory(dorm_id, building, room_type, capacity)  # 调用宿舍管理器添加宿舍
            print("✓ 宿舍添加成功")  # 输出成功提示信息
        except ValueError as e:  # 捕获数据验证异常
            print(f"✗ 添加失败: {e}")  # 输出验证失败错误信息
        except Exception as e:  # 捕获其他系统异常
            print(f"✗ 系统错误: {e}")  # 输出系统错误信息
    
    def view_all_dormitories(self):
        print("\n所有宿舍信息")
        dormitories = DormitoryManager.get_all_dormitories()
        
        if not dormitories:
            print("暂无宿舍信息")
            return
        
        table = PrettyTable(["宿舍号", "楼栋", "房间类型", "容量", "已住人数", "剩余床位"])
        for dorm_id, info in dormitories.items():
            remaining = info['capacity'] - info['occupied']
            table.add_row([
                dorm_id, info['building'], info['room_type'], 
                info['capacity'], info['occupied'], remaining
            ])
        print(table)
    
    def assign_dormitory(self):
        print("\n分配宿舍")
        student_id = input("请输入学号: ")
        dorm_id = input("请输入宿舍号: ")
        
        try:
            DormitoryManager.assign_dormitory(student_id, dorm_id)
            print("宿舍分配成功")
        except ValueError as e:
            print(f"分配失败: {e}")
    
    def view_available_dormitories(self):
        print("\n可用宿舍")
        dormitories = DormitoryManager.get_available_dormitories()
        
        if not dormitories:
            print("暂无可用宿舍")
            return
        
        table = PrettyTable(["宿舍号", "楼栋", "房间类型", "容量", "已住人数", "剩余床位"])
        for dorm_id, info in dormitories.items():
            remaining = info['capacity'] - info['occupied']
            table.add_row([
                dorm_id, info['building'], info['room_type'], 
                info['capacity'], info['occupied'], remaining
            ])
        print(table)
    
    def registration_management(self):
        while True:
            print("\n报道管理")
            print("【1】办理报道")
            print("【2】查看报道记录")
            print("【3】返回上级菜单")
            
            choice = input("请选择操作: ")
            
            if choice == '1':
                self.process_registration()
            elif choice == '2':
                self.view_registration_records()
            elif choice == '3':
                break
            else:
                print("无效选择，请重新输入")
    
    def process_registration(self):
        print("\n办理报道")
        student_id = input("请输入学号: ")
        
        try:
            student = StudentManager.get_student_info(student_id)
            if not student:
                print("学生不存在")
                return
            
            if student['status'] == '已报道':
                print("该学生已经报道")
                return
            
            print(f"学生信息: {student['name']} - {student['major']}")
            confirm = input("确认办理报道吗？(y/n): ")
            
            if confirm.lower() == 'y':
                StudentManager.mark_registration(student_id, self.current_user)
                print("报道办理成功")
            else:
                print("操作取消")
        except ValueError as e:
            print(f"办理失败: {e}")
    
    def view_registration_records(self):
        print("\n报道记录")
        records = data_manager.load_registration_records()
        
        if not records:
            print("暂无报道记录")
            return
        
        table = PrettyTable(["学号", "报道时间", "经办人"])
        for record in records:
            table.add_row([record['student_id'], record['time'], record['operator']])
        print(table)
    
    def statistics_query(self):
        while True:
            print("\n统计查询")
            print("【1】学生报道统计")
            print("【2】宿舍使用统计")
            print("【3】返回上级菜单")
            
            choice = input("请选择操作: ")
            
            if choice == '1':
                self.student_statistics()
            elif choice == '2':
                self.dormitory_statistics()
            elif choice == '3':
                break
            else:
                print("无效选择，请重新输入")
    
    def student_statistics(self):
        print("\n学生报道统计")
        total, registered, unregistered = StudentManager.get_statistics()
        
        table = PrettyTable(["统计项目", "数量"])
        table.add_row(["学生总数", total])
        table.add_row(["已报道", registered])
        table.add_row(["未报道", unregistered])
        
        if total > 0:
            registration_rate = (registered / total) * 100
            table.add_row(["报道率", f"{registration_rate:.1f}%"])
        
        print(table)
    
    def dormitory_statistics(self):
        print("\n宿舍使用统计")
        dormitories = DormitoryManager.get_all_dormitories()
        
        if not dormitories:
            print("暂无宿舍信息")
            return
        
        total_capacity = sum(info['capacity'] for info in dormitories.values())
        total_occupied = sum(info['occupied'] for info in dormitories.values())
        total_available = total_capacity - total_occupied
        
        table = PrettyTable(["统计项目", "数量"])
        table.add_row(["宿舍总数", len(dormitories)])
        table.add_row(["总床位", total_capacity])
        table.add_row(["已使用", total_occupied])
        table.add_row(["剩余床位", total_available])
        
        if total_capacity > 0:
            occupancy_rate = (total_occupied / total_capacity) * 100
            table.add_row(["使用率", f"{occupancy_rate:.1f}%"])
        
        print(table)

def main():  # 程序主函数，系统启动入口
    try:  # 使用try-except结构处理系统运行中的异常
        system = SystemInterface()  # 创建系统界面实例
        print("=" * 50)  # 输出分隔线美化界面
        print("         欢迎使用高校新生报道系统")  # 输出系统欢迎标题
        print("=" * 50)  # 输出分隔线
        print("系统功能：")  # 输出功能介绍标题
        print("• 学生信息管理")  # 列出学生信息管理功能
        print("• 宿舍分配管理")  # 列出宿舍分配管理功能
        print("• 报道流程管理")  # 列出报道流程管理功能
        print("• 统计查询功能")  # 列出统计查询功能
        print("=" * 50)  # 输出分隔线
        system.main_menu()  # 启动主菜单进入系统
    except KeyboardInterrupt:  # 捕获用户按Ctrl+C中断程序的异常
        print("\n\n用户取消操作，系统退出。")  # 输出用户主动退出的提示信息
    except Exception as e:  # 捕获其他未预期的系统异常
        print(f"\n系统运行出现异常: {e}")  # 输出系统异常信息
        print("请联系系统管理员解决问题。")  # 提示用户联系管理员

if __name__ == "__main__":  # Python程序标准入口判断，确保只有直接运行该文件时才执行主函数
    main()  # 调用主函数启动系统